﻿Imports System
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports System.Runtime.Remoting.Messaging
Imports System.Workflow.ComponentModel
Imports System.Workflow.Runtime

Namespace System.Workflow.Activities
    Friend Class InboundActivityHelper
        ' Methods
        Friend Shared Function DequeueMessage(ByVal queueId As IComparable, ByVal queueSvcs As WorkflowQueuingService, ByVal activity As Activity, <Out> ByRef queue As WorkflowQueue) As Object
            Dim obj2 As Object = Nothing
            queue = queueSvcs.GetWorkflowQueue(queueId)
            If (queue.Count <> 0) Then
                obj2 = queue.Dequeue
                If (obj2 Is Nothing) Then
                    Throw New ArgumentException(SR.GetString("Error_InvalidEventMessage", New Object() { activity.QualifiedName }))
                End If
            End If
            Return obj2
        End Function

        Friend Shared Function ExecuteForActivity(ByVal activity As HandleExternalEventActivity, ByVal context As ActivityExecutionContext, ByVal interfaceType As Type, ByVal operation As String, <Out> ByRef args As Object()) As ActivityExecutionStatus
            Dim queueSvcs As WorkflowQueuingService = DirectCast(context.GetService(GetType(WorkflowQueuingService)), WorkflowQueuingService)
            args = Nothing
            Dim queueId As IComparable = CorrelationService.ResolveQueueName(activity, interfaceType, operation)
            If (Not queueId Is Nothing) Then
                Dim queue As WorkflowQueue
                Dim msg As Object = InboundActivityHelper.DequeueMessage(queueId, queueSvcs, activity, queue)
                CorrelationService.UninitializeFollowers(interfaceType, operation, queue)
                If (Not msg Is Nothing) Then
                    args = InboundActivityHelper.ProcessEvent(activity, context, msg, interfaceType, operation)
                    Return ActivityExecutionStatus.Closed
                End If
            End If
            Return ActivityExecutionStatus.Executing
        End Function

        Private Shared Function ProcessEvent(ByVal activity As HandleExternalEventActivity, ByVal context As ActivityExecutionContext, ByVal msg As Object, ByVal interfaceType As Type, ByVal operation As String) As Object()
            Dim message As IMethodMessage = [TryCast](msg,IMethodMessage)
            If (message Is Nothing) Then
                Dim exception As Exception = [TryCast](msg,Exception)
                If (Not exception Is Nothing) Then
                    Throw exception
                End If
                Throw New InvalidOperationException(SR.GetString("Error_InvalidLocalServiceMessage"))
            End If
            CorrelationService.InvalidateCorrelationToken(activity, interfaceType, operation, message.Args)
            Dim data As IdentityContextData = DirectCast(message.LogicalCallContext.GetData("__identitycontext__"), IdentityContextData)
            InboundActivityHelper.ValidateRoles(activity, data.Identity)
            If InboundActivityHelper.ProcessEventParameters(activity.ParameterBindings, message, interfaceType, operation) Then
                Return message.Args
            End If
            Return Nothing
        End Function

        Private Shared Function ProcessEventParameters(ByVal parameters As WorkflowParameterBindingCollection, ByVal message As IMethodMessage, ByVal interfaceType As Type, ByVal operation As String) As Boolean
            Dim flag As Boolean = False
            If (Not parameters Is Nothing) Then
                Dim method As MethodInfo = interfaceType.GetEvent(operation).EventHandlerType.GetMethod("Invoke")
                Dim index As Integer = 0
                Dim info3 As ParameterInfo
                For Each info3 In method.GetParameters
                    If (GetType(ExternalDataEventArgs).IsAssignableFrom(info3.ParameterType) AndAlso (index = 1)) Then
                        flag = True
                    End If
                    If parameters.Contains(info3.Name) Then
                        Dim binding As WorkflowParameterBinding = parameters.Item(info3.Name)
                        binding.Value = message.Args(index)
                    End If
                    index += 1
                Next
            End If
            Return flag
        End Function

        Friend Shared Sub ValidateRoles(ByVal activity As Activity, ByVal identity As String)
            Dim dependencyProperty As DependencyProperty = DependencyProperty.FromName("Roles", activity.GetType.BaseType)
            If (dependencyProperty Is Nothing) Then
                dependencyProperty = DependencyProperty.FromName("Roles", activity.GetType)
            End If
            If (Not dependencyProperty Is Nothing) Then
                Dim binding As ActivityBind = activity.GetBinding(dependencyProperty)
                If (Not binding Is Nothing) Then
                    Dim runtimeValue As WorkflowRoleCollection = [TryCast](binding.GetRuntimeValue(activity),WorkflowRoleCollection)
                    If ((Not runtimeValue Is Nothing) AndAlso Not runtimeValue.IncludesIdentity(identity)) Then
                        Throw New WorkflowAuthorizationException(activity.Name, identity)
                    End If
                End If
            End If
        End Sub

    End Class
End Namespace

